#pragma once
#include <iostream>
#include <unordered_map>
#include <vector>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "log.hpp"

const int BUF_MAX_SIZE = 40960;

class Util
{
public:
    // 解决粘包问题
    static int ReadHttpRequest(const int &cfd, std::string &inbuf, std::string *request)
    {
        // http报文的分隔符
        const std::string SEP = "\r\n";
        const int SEP_LEN = SEP.size();
        const std::string DSEP = "\r\n\r\n";
        const int DSEP_LEN = 2 * SEP_LEN;

        // 1 从接收缓冲区提取一段字节流数据
        char buf[1024] = {0};
        ssize_t n = recv(cfd, buf, sizeof(buf) - 1, 0);
        if (n <= 0)
        {
            return 1;
        }
        // buf数据可能存在\0, 不能直接赋值给inbuf字符串
        buf[n] = 0;
        std::string bufstr;
        bufstr.resize(n);
        memcpy((char *)bufstr.c_str(), buf, n);
        inbuf += bufstr;

        LogMessage(DEBUG, "cur inbuf: %s\n", inbuf.c_str());

        // 关键：判断当前读取字节流中是否含有一个完整http请求报文

        // 2 跳过请求行，找到报头字段
        int firstSepPos = inbuf.find(SEP);
        if (firstSepPos == std::string::npos)
        {
            return 2;
        }
        int reqLineLen = firstSepPos;

        // 3 获取一个完整的报头字段区间，以空行结尾
        int headersBegin = firstSepPos + SEP_LEN;
        if (headersBegin >= inbuf.size())
        {
            return 3;
        }
        if (inbuf[headersBegin] == SEP[0])
        {
            // 无报头的情况
            *request = inbuf.substr(0, reqLineLen + DSEP_LEN);
            return 4;
        }

        int headersEnd = inbuf.find(DSEP, headersBegin);
        if (headersEnd == std::string::npos)
        {
            // 报头字段不完整
            return 5;
        }
        std::string headers = inbuf.substr(headersBegin, headersEnd - headersBegin);

        // 5 查看报头字段中有无Content-Length，有则更新bodyLen
        int bodyLen = 0;
        int contLenPos = headers.find("Content-Length: ");
        if (contLenPos != std::string::npos)
        {
            // 有Content-Length
            contLenPos += strlen("Content-Length: ");
            int contLenEnd = headers.find(SEP, contLenPos);
            bodyLen = std::stoi(headers.substr(contLenPos, contLenEnd - contLenPos));
        }

        // 6 此时已经得知当前报文的长度，比对inbuf够不够
        int reqLen = reqLineLen + SEP_LEN + headers.size() + DSEP_LEN + bodyLen;
        if (reqLen > inbuf.size())
        {
            return 6;
        }
        std::string httpRequest = inbuf.substr(0, reqLen);
        inbuf.erase(0, reqLen);
        *request = httpRequest;
        return 0;
    }

    // static bool ReadHttpRequest(const int &cfd, std::string *request)
    // {
    //     // 如何确保获取一个完整的报文？TODO
    //     char inbuf[1024] = {0};
    //     ssize_t n = recv(cfd, inbuf, sizeof(inbuf) - 1, 0);
    //     if (n <= 0)
    //     {
    //         return false;
    //     }
    //     LogMessage(DEBUG, "读取请求成功\n");
    //     inbuf[n] = 0;

    //     request->resize(n);
    //     memcpy((char *)request->c_str(), inbuf, n);
    //     return true;
    // }

    static bool SendHttpResponse(const int &cfd, const std::string &response)
    {
        ssize_t n = send(cfd, response.c_str(), response.size(), 0);
        if (n <= 0)
        {
            return false;
        }
        LogMessage(DEBUG, "发送响应成功\n");
        return true;
    }

    static bool ReadOneLine(std::string &lines, std::string *line, const std::string &sep)
    {
        size_t pos = lines.find(sep);
        if (pos == std::string::npos)
        {
            return false; // 404TODO
        }

        // 提取lines中的一行
        *line = lines.substr(0, pos);
        lines.erase(0, pos + sep.size()); // 把分隔符也去掉

        return true;
    }

    static std::pair<std::string, std::string> ParseHeader(const std::string &header)
    {
        const static std::string sep = ": ";
        size_t pos = header.find(sep);
        std::string key = header.substr(0, pos);
        std::string value = header.substr(pos + sep.size(), header.size() - pos - sep.size());
        return std::make_pair(key, value);
    }

    static int ReadFileContent(const std::string &path, std::string *out)
    {
        // 用户请求的资源可能不存在,客户端错误,响应状态码404
        int fd = open(path.c_str(), O_RDONLY);
        if (fd < 0)
        {
            return -1; // 404TODO
        }

        char buf[BUF_MAX_SIZE] = {0};
        ssize_t n = read(fd, buf, sizeof(buf) - 1);
        if (n < 0)
        {
            // 这里是server error
            return -2;
        }
        buf[n] = '\0';

        out->resize(n);
        memcpy((char *)out->c_str(), buf, n);

        close(fd);
        return n;
    }

    static std::string GetTypeBySuffix(const std::string &suffix) // 404TODO
    {
        if (".html" == suffix)
            return "text/html";
        if (".jpg" == suffix)
            return "image/jpeg";
        if (".png" == suffix)
            return "image/png";
        if (".mp4" == suffix)
            return "video/mpeg4";
        if (".jpg" == suffix)
            return "image/jpeg";
        else
            return std::string();
    }

    static bool GetUsernamePasswd(std::string body, std::string *username, std::string *passwd)
    {
        // "username=kfChen&password=1234"
        size_t sep_pos = body.find('&');

        size_t pos1 = body.rfind('=', sep_pos) + 1;
        *username = body.substr(pos1, sep_pos - pos1);

        size_t pos2 = body.find('=', sep_pos);
        *passwd = body.substr(sep_pos + 1, pos2 - sep_pos - 1);
        return true;
    }

    static bool CheckUser(const std::string &username, const std::string &passwd, const std::unordered_map<std::string, std::string> &ups)
    {
        auto it = ups.find(username);
        return it != ups.end();
    }
};